/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
aLONG with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "commonheaders.h"
#include "ExtraServices.h"
#include "m_protocols.h"
#include "m_png.h"
#include "m_avatars.h"

namespace NServices {
namespace NAvatar {

int SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName ) 
{
	BITMAPINFO* bmi;
	HDC hdc;
	HBITMAP hOldBitmap;
	BITMAPINFOHEADER* pDib;
	BYTE* pDibBits;
	long dwPngSize = 0;
	DIB2PNG convertor;
	
	if(!ServiceExists(MS_DIB2PNG)) {
		MsgErr(NULL, TranslateT("Your png2dib.dll is either obsolete or damaged."));
		return 1;
	}

	hdc = CreateCompatibleDC( NULL );
	hOldBitmap = ( HBITMAP )SelectObject( hdc, hBitmap );

	bmi = (BITMAPINFO*)_alloca(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256);
	memset(bmi, 0, sizeof(BITMAPINFO));
	bmi->bmiHeader.biSize = 0x28;
	if(GetDIBits(hdc, hBitmap, 0, 96, NULL, bmi, DIB_RGB_COLORS) == 0) {
		return 2;
	}

	pDib = (BITMAPINFOHEADER*)GlobalAlloc(LPTR, sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256 + bmi->bmiHeader.biSizeImage);
	if(pDib == NULL)
		return 3;

	memcpy(pDib, bmi, sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256);
	pDibBits = ((BYTE*)pDib) + sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256;

	GetDIBits(hdc, hBitmap, 0, pDib->biHeight, pDibBits, (BITMAPINFO*)pDib, DIB_RGB_COLORS);
	SelectObject(hdc, hOldBitmap);
	DeleteDC(hdc);

	convertor.pbmi = ( BITMAPINFO* )pDib;
	convertor.pDiData = pDibBits;
	convertor.pResult = NULL;
	convertor.pResultLen = &dwPngSize;
	if(!CallService(MS_DIB2PNG, 0, (LPARAM)&convertor)) {
		GlobalFree(pDib);
		return 2;
	}

	convertor.pResult = (PBYTE)mir_alloc(dwPngSize);
	CallService(MS_DIB2PNG, 0, (LPARAM)&convertor);

	GlobalFree(pDib);
	{	
		FILE* out;
		
		out = fopen(szFileName, "wb");
		if(out != NULL) {
			fwrite(convertor.pResult, dwPngSize, 1, out);
			fclose(out);
		}	
	}
	mir_free(convertor.pResult);

	return ERROR_SUCCESS;
}

static INT GetContactAvatarFileName(LPCTSTR zodiac, LPSTR szFileName, INT cchFileName)
{
	if(!CallService(MS_DB_GETPROFILEPATH, (WPARAM)cchFileName, (LPARAM)szFileName)) {
		int len = mir_strlen(szFileName);

#ifdef _UNICODE
		CHAR tmp[64];
		
		WideCharToMultiByte(CP_ACP, 0, zodiac, -1, tmp, SIZEOF(tmp),0,0);
		return cchFileName <= mir_snprintf(szFileName + len, cchFileName - len, "\\avatars\\%s.png", tmp);
#else
		return cchFileName <= mir_snprintf(szFileName + len, cchFileName - len, "\\avatars\\%s.png", zodiac);
#endif
	}
	return 1;
}

static VOID SetZodiacAvatar(HANDLE hContact, AVATARCACHEENTRY *ace) 
{
	if(!DBSettingExists(hContact, "ContactPhoto", "File")) {

	//if(!ace || !(ace->dwFlags & AVS_BITMAP_VALID)) {
		MAnnivDate mtb;

		// try to load birthday for contact
		if(!mtb.DBGetBirthDate(hContact)) {
			MZodiac zodiac;
			ICONINFO iinfo;
			CHAR szFileName[MAX_PATH];
			
			// get zodiac for birthday
			zodiac = mtb.Zodiac();

			if(!GetContactAvatarFileName(zodiac.pszName, szFileName, SIZEOF(szFileName))) {

				// extract the bitmap from the icon
				GetIconInfo(zodiac.hIcon, &iinfo);

				// save the bitmap to a file used as avatar later
				if(!SaveBitmapAsAvatar(iinfo.hbmColor, szFileName)) {

					CallService(MS_AV_SETAVATAR, (WPARAM)hContact, (LPARAM)szFileName);
				}
			}
		}
	}
}

static VOID CheckAllContacts()
{
	if(ServiceExists(MS_AV_GETAVATARBITMAP)) {
		HANDLE hContact;
		AVATARCACHEENTRY *ace;
		
		//walk through all the contacts stored in the DB
		for(hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
			hContact != NULL;
			hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0))
		{
			ace = (AVATARCACHEENTRY*)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, NULL);
			SetZodiacAvatar(hContact, ace);
		}
	}
}


static INT OnAvatarChanged(WPARAM wParam, LPARAM lParam)
{
	SetZodiacAvatar((HANDLE)wParam, (AVATARCACHEENTRY *)lParam);
	return 0;
}


/**
 * name:	OnModulesLoaded
 * desc:	initialize stuff, which require all standard modules to bee loaded
 * params:	none
 * return:	0
 **/
VOID OnModulesLoaded()
{
	if(ServiceExists(MS_AV_GETAVATARBITMAP)) {
		HookEvent(ME_AV_AVATARCHANGED, OnAvatarChanged);
		CheckAllContacts();
	}
}

} /* namespace NAvatar */
} /* namespace NServices */